package com.anos.smsfun.controller;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.os.Handler;

/**
 * ThreadManager: mọi xử lý background đều được đưa vào Threadpool
 * 
 * @author Trinh Minh Soan (tmsoan@gmail.com)
 * 
 */

public class ThreadManager {

	// Singleton
	private static ThreadManager mInstance;

	private static final Object mLock = new Object();

	/**
	 * Số lượng thread trong thread pool
	 */
	private static final int CORE_POOL_SIZE = 4;

	/**
	 * Số lượng thread tối đa trong pool
	 */
	private static final int MAXIMUM_POOL_SIZE = 4;

	/**
	 * Thời gian giữ một thread tồn tại để chờ dùng lại sau khi thực thi xong
	 */
	private static final int KEEP_ALIVE_TIME = 2;

	/**
	 * Hàng đợi các task cần thực thi với thread pool
	 */
	private final BlockingQueue<Runnable> mTaskQueue;

	/**
	 * Thread pool để xử lý các task
	 */
	private final ThreadPoolExecutor mTaskThreadPool;

	/**
	 * Handler để gửi callback kết quả lên UI thread
	 */
	private Handler mUICallbackHandler;

	public static ThreadManager getInstance(Context context) {
		synchronized (mLock) {
			if (mInstance == null) {
				mInstance = new ThreadManager(context.getApplicationContext());
			}
			return mInstance;
		}
	}

	private ThreadManager(Context context) {
		mTaskQueue = new LinkedBlockingQueue<Runnable>();
		mTaskThreadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
				MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
				mTaskQueue);
		mTaskThreadPool.allowCoreThreadTimeOut(true);

		// UI worker handler
		mUICallbackHandler = new Handler(context.getMainLooper());
	}

	/**
	 * Gửi yêu cầu thực thi một công việc nào đó
	 */
	public void execute(Runnable runnable) {
		mTaskThreadPool.execute(runnable);
	}

	/**
	 * Hoãn thực thi một task nào đó
	 */
	public void cancel(Runnable runnable) {
		mTaskThreadPool.remove(runnable);
	}

	/**
	 * Thực hiện callback báo kết quả trên UI thread
	 * 
	 * @param result
	 *            object callback có kèm kết quả
	 * @param continueWaiting
	 *            liệu bên chờ kết quả có cần chờ tiếp kết quả nữa hay không,
	 *            trong trường hợp dữ liệu trả về 2 lần, một lần từ cache và một
	 *            lần từ server
	 */
	public <T extends Object> void callbackOnUIThread(
			final DataRequestCallback<T> resultCallback, final T result,
			final boolean continueWaiting) {
		resultCallback.setResult(result);
		mUICallbackHandler.post(new Runnable() {
			@Override
			public void run() {
				resultCallback.onResult(continueWaiting);
			}
		});
	}
}
